/**
 * @author raohj
 * @date 2018年10月30日
 * @file RNioClient.java
 * @comment : please input your comment to this file
 * @version : input version
 * @modify:
 * 		1、 2018年10月30日 由 raohj 新建文件
 */
package com.ccnu.demojava.net.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

/**
 * @author raohj
 * @date 2018年10月30日
 * @version 
 */
public class RNioClient {
	/**
	 * @author raohj
	 * @date 2018年10月30日
	 * @version 
	 */
	public class RTimeClient implements Runnable{
		private String host;
		private int port;
		private Selector seltor;
		private SocketChannel socketchan;
		private volatile boolean stop;
		
		public boolean getStop() {
			return stop;
		}

		public void setStop(boolean stop) {
			this.stop = stop;
		}

		/**
		 * @param host
		 * @param port
		 */
		public RTimeClient(String host, int port) {
			super();
			this.host = host;
			this.port = port;
			try {
				seltor = Selector.open();	// 创建一个选择器
				socketchan = SocketChannel.open();	// 创建一个通道
				socketchan.configureBlocking(false);	// 设置为非堵塞
			}
			catch (Exception e) {
				e.printStackTrace();
				System.exit(1);
			}
		}

		/* (non-Javadoc)
		 * @see java.lang.Runnable#run()
		 */
		public void run() {
			// TODO Auto-generated method stub
			try {
				doConnect();
			}
			catch (Exception e) {
				// TODO: handle exception
				System.exit(1);
			}
			
			while(!this.getStop()) {
				try {
					seltor.select(1000);
					Set<SelectionKey> selectedKey = seltor.selectedKeys();
					Iterator<SelectionKey> it = selectedKey.iterator();
					SelectionKey key = null;
					while(it.hasNext()) {
						key = it.next();
						it.remove();
						try {
							handInput(key);
						}
						catch (Exception e) {
							if(key != null) {
								key.cancel();
								if(key.channel() != null) {
									key.channel().close();
								}
							}
						}
					}
				}
				catch (Exception e) {
					e.printStackTrace();
					System.exit(1);
				}
			}
			
			if(seltor != null) {
				try {
					seltor.close();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}

		/**
		 * @author raohj
		 * @date 2018年10月30日
		 * @comment 连接服务器
		 * @param 
		 * @return 
		 */
		public void doConnect() throws IOException {
			// 如果直接连接成功，则准备写入数据
			if(socketchan.connect(new InetSocketAddress(this.host, this.port))){
				socketchan.register(seltor, SelectionKey.OP_READ);
				doWrite(socketchan);
			}
			else {
				socketchan.register(seltor, SelectionKey.OP_CONNECT);
			}
		}
		
	    /**
	     * @author raohj
	     * @date 2018年10月30日
	     * @comment 写入通道
	     * @param 
	     * @return 
	     * @param channel
	     * @param req
	     * @throws IOException
	     */
	    public void doWrite(SocketChannel channel) 
	    	throws IOException{
	    	String req = new String("give me a help\n");
	    	if(req != null && req.trim().length()>0) {
	    		byte [] bytes = req.getBytes();
	    		ByteBuffer writeBuffer = ByteBuffer.allocate(bytes.length);
	    		writeBuffer.put(bytes);
	    		writeBuffer.flip();
	    		channel.write(writeBuffer);
	    	}
	    }
		
	    /**
	     * @author raohj
	     * @date 2018年10月30日
	     * @comment add your comment
	     * @param 
	     * @return 
	     * @param key
	     * @throws IOException
	     */
	    private void handInput(SelectionKey key) throws IOException{
	        if(key.isValid()){
	        	SocketChannel sc = (SocketChannel) key.channel();
	        	// 判断是否连接成功
	        	if(sc.isConnected()) {
	        		if(sc.finishConnect()) {
	        			sc.register(seltor, SelectionKey.OP_READ);
	        			doWrite(sc);
	        		}
	        		else {
	        			System.exit(1);
	        		}
	        	}
	            // 如果是读请求
	            if(key.isReadable()){
	                ByteBuffer readBuffer = ByteBuffer.allocate(1024);
	                int readByte = sc.read(readBuffer);
	                if(readByte>0){
	                    readBuffer.clear();
	                    readBuffer.put(new String("[" + Thread.currentThread().threadId() + "]" + "this is my Server, Please deal later\n").getBytes());
	                    readBuffer.flip();
	                    sc.write(readBuffer);
	                    key.channel().close();
	                    sc.close();
	                }
	                else if( readByte<0) {
	                	// 对端链路关闭，取消对此通道的监听
	                	key.cancel();
	                    sc.close();
	                }
	                else { // readByte == 0
	                	// 已经读取完毕了
	                }
	            }
	        }
	    }
		
	}
}
